package cn.efunbox.afw.core.entity.tree;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONField;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
/**
 * 
 * @author list 转 treeNode
 */
public class TreeNode {

    private String name;
    private String parentId;
    private String title;
    private String path;
    @JSONField(serialize=false)
    private String code;

    private Boolean leaf;
    private Boolean own;
    private List<TreeNode> items;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getParentId() {
        return parentId;
    }

    public void setParentId(String parenrtId) {
        this.parentId = parenrtId;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public Boolean getLeaf() {
        return leaf;
    }

    public void setLeaf(Boolean leaf) {
        this.leaf = leaf;
    }

    public List<TreeNode> getItems() {
        return items;
    }

    public void setItems(List<TreeNode> items) {
        this.items = items;
    }
    public Boolean getOwn() {
        return own;
    }

    public void setOwn(Boolean own) {
        this.own = own;
    }

    public TreeNode() {
        super();
    }

    public TreeNode(Long name, Long parentId, String title, String path, String code, Integer leaf,Boolean own) {
        this.name = String.valueOf(name);
        this.parentId = String.valueOf(parentId);
        this.title = title;
        this.path = path;
        this.code = code;
        this.leaf = leaf==2?true:false;
        this.own = own;
    }
    public TreeNode(String name, String parentId, String title, String path, String code, Boolean leaf) {
        this.name = name;
        this.parentId = parentId;
        this.title = title;
        this.path = path;
        this.code = code;
        this.leaf = leaf;
    }

    public TreeNode(String name, String parentId, String title, String path, String code, Boolean leaf, List<TreeNode> items) {
        this.name = name;
        this.parentId = parentId;
        this.title = title;
        this.path = path;
        this.code = code;
        this.leaf = leaf;
        this.items = items;
    }

    public static <T extends TreeNode> List<TreeNode> getTree(List<T> nodeList) {
        /**
         * 定义“数组-链表”，该数组链表的每一项相当于一深度为2的小树
         * Map的key相当于“数组”的某一项，Map的value相当于该key所拥有的“链表”
         * 这里，key为父节点ID，list为具有相同父节点ID的所有同级子节点实体list（属于该父节点的所有子节点）
         */
        Map<String, List<TreeNode>> arrayListMap = new HashMap<String, List<TreeNode>>();
        TreeNode node=null;
        for (TreeNode e : nodeList) {
            // 变量定义务必在循环内，对象是引用，不能重复使用同一个对象变量
            node = new TreeNode();
            node.setName(e.getName());
            node.setTitle(e.getTitle());
            node.setCode(e.getCode());
            node.setLeaf(e.getLeaf());
            node.setPath(e.getPath());
            node.setOwn(e.getOwn());
            node.setParentId(e.getParentId());
            String fatherId = e.getParentId();
            // 获取当前遍历结点的父ID，并判断该父节点的数组链表项是否存在，如果该“数组项-链表项”不存在，则新建一个，并放入“数组-链表”
            if (arrayListMap.get(fatherId) == null) {
                List<TreeNode> list = new ArrayList<TreeNode>();
                list.add(node);
                arrayListMap.put(fatherId, list);
            } else {
                List<TreeNode> valueList = arrayListMap.get(fatherId);
                valueList.add(node);
                arrayListMap.put(fatherId, valueList);
            }
            node=null;
        }
        // 以上，至此，第一遍遍历完毕，非叶子节点都拥有一个“数组-链表项”，也即“最小的树”已创建完毕
 
        // 以下，对“数组链表”Map进行遍历，更改“最小的树”的从属关系（更改指针指向），也即把所有小树组装成大树
        for (Map.Entry<String, List<TreeNode>> entry : arrayListMap.entrySet()) {
            // 获取当前遍历“数组项-链表项”的链表项，并对链表项进行遍历，从“数组-链表”小树中找到它的子节点，并将该子节点加到该小树的children中
            List<TreeNode> smallTreeList = new ArrayList<TreeNode>();
            smallTreeList = entry.getValue();
            int nodeListSize = smallTreeList.size();
            for (int i = 0; i < nodeListSize; i++) {
                String findID = smallTreeList.get(i).getName();
                List<TreeNode> findList = arrayListMap.get(findID);
                // 以下操作不能取出对象存放在变量中，否则将破坏树的完整性
                smallTreeList.get(i).setItems(findList);
            }
        }
        // 获取以0为父Id的链表项，该链表项是根节点实体，里面已封装好各子节点，可以由于多个根节点，即这些根结点的父Id都为0
        return   arrayListMap.get("0");
    }

    public static void main(String[] args) {

        List<TreeNode> list=new ArrayList<>();
        TreeNode  temp =null;
        for(int i=0; i<3;i++){
            for (int j=0;j<3;j++){
                for (int k=0;k<3;k++){
                    if (i*3+j*3+k==0){
                        continue;
                    }
                    temp= new TreeNode();
                    if ((i*9+j*3+k)%3==0){
                        if ((i*9+j*3+k)%9==0){
                            temp.setParentId(""+i);
                        }else {
                            temp.setParentId(""+(i*3+j));
                        }
                        temp.setLeaf(false);
                    }else {
                        temp.setParentId(""+(i*9+j*3));
                        temp.setLeaf(true);
                    }
                    temp.setName(""+(i*9+j*3+k));
                    temp.setPath("path"+(i*9+j*3+k));
                    temp.setTitle("title"+(i*9+j*3+k));
                    temp.setCode("code"+(i*9+j*3+k));
                    temp.setOwn(Boolean.TRUE);
                    System.out.println(JSON.toJSONString(temp));
                    list.add(temp);
                    temp=null;
                }
            }
        }
        List<TreeNode> tree = TreeNode.getTree(list);
        System.out.println(JSON.toJSONString(tree));
    }
}